package red.stu.pconstraint;

import com.alibaba.fastjson.JSONObject;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import red.stu.pconstraint.dto.mapper.ProcessMapper;
import red.stu.pconstraint.engine.*;
import red.stu.pconstraint.pojo.ExecutionLocation;
import red.stu.pconstraint.pojo.ProcessStorage;

import java.io.IOException;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.UUID;

/**
 * @author yihrmc @stu.red
 * @date 2019/11/21 15:11
 */
public class ProcessUtils {

    /**
     * 工厂实例
     */
    public static WorkFlowEngineFactory INSTANCE;

    static {
        try {
            INSTANCE = new WorkFlowEngineFactory(new AbstractProcessStorageFactory() {
                @Override
                public @NotNull ProcessStorageApi getProcessStorage(ProcessMapper processMapper) {
                    return new ProcessStorageApi() {

                        private HashMap<String, ProcessStorage> testStorage = new HashMap<>();

                        @Override
                        public @NotNull String createProcessData(@NotNull ProcessStorage processStorage, @NotNull WorkingSpace workingSpace) {
                            System.out.println("ProcessStorageApi - createProcessData: " + JSONObject.toJSONString(processStorage));
                            String processInstanceId = UUID.randomUUID().toString();
                            testStorage.put(processInstanceId, processStorage);
                            return processInstanceId;
                        }

                        @Override
                        public @Nullable ProcessStorage getProcessData(String processInstanceId) {
                            System.out.println("ProcessStorageApi - getProcessData");
                            return testStorage.get(processInstanceId);
                        }

                        @Override
                        public @Nullable Short getState(String processInstanceId) {
                            ProcessStorage processStorage = testStorage.get(processInstanceId);
                            if (processStorage == null) {
                                return null;
                            }
                            return processStorage.getState();
                        }

                        @Override
                        public void updateProcessCallStack(String processInstanceId, LinkedList<ExecutionLocation> callStack) {
                            System.out.println("ProcessStorageApi - updateProcessCallStack: " + JSONObject.toJSONString(callStack));
                            ProcessStorage processStorage = testStorage.get(processInstanceId);
                            if (processStorage == null) {
                                throw new RuntimeException("更新流程失败!");
                            }
                            processStorage.setCallStack(callStack);
                        }

                        @Override
                        public void updateState(String processInstanceId, Short state) {
                            System.out.println("ProcessStorageApi - updateState: processInstanceId["
                                    + processInstanceId + "] state[" + state + "]");
                            ProcessStorage processStorage = testStorage.get(processInstanceId);
                            if (processStorage == null) {
                                throw new RuntimeException("更新流程失败!");
                            }
                            processStorage.setState(state);
                        }

                        @Override
                        public void updateStateAndCallStack(String processInstanceId, Short state, LinkedList<ExecutionLocation> callStack) {
                            System.out.println("ProcessStorageApi - updateStateAndCallStack: processInstanceId["
                                    + processInstanceId + "] state[" + state + "] callStack[" + JSONObject.toJSONString(callStack) + "]");
                            ProcessStorage processStorage = testStorage.get(processInstanceId);
                            if (processStorage == null) {
                                throw new RuntimeException("更新流程失败!");
                            }
                            processStorage.setState(state);
                            processStorage.setCallStack(null);
                        }

                    };
                }
            }, new BaseProcessEventListener() {
                @Override
                public void onCreated(@NotNull ProcessStorage processStorage, @NotNull WorkFlowEngine workFlowEngine) {
                    System.out.println("#流程创建");
                }

                @Override
                public void onChanged(@NotNull List<ExecutionLocation> callStack, @NotNull String processInstanceId, @NotNull WorkFlowEngine workFlowEngine) {
                    System.out.println("#流程切换");
                }

                @Override
                public void onSuspended(@Nullable String processInstanceId, @NotNull WorkFlowEngine workFlowEngine) {
                    System.out.println("#流程被挂起");
                }

                @Override
                public void onSuspendedRecovery(@Nullable String processInstanceId, @NotNull WorkFlowEngine workFlowEngine) {
                    System.out.println("#流程挂起恢复");
                }

                @Override
                public void onSuccess(@Nullable String processInstanceId, @NotNull WorkFlowEngine workFlowEngine) {
                    System.out.println("#流程处理成功");
                }

                @Override
                public void onFail(@Nullable String processInstanceId, @NotNull WorkFlowEngine workFlowEngine) {
                    System.out.println("#流程处理失败");
                }

                @Override
                public void onComplete(@Nullable String processInstanceId, @NotNull WorkFlowEngine workFlowEngine) {
                    System.out.println("#流程处理完成");
                }

                @Override
                public void onThrowException(Exception exception, @Nullable String processInstanceId, @NotNull WorkFlowEngine workFlowEngine) {
                    System.out.println("#流程出现异常(" + processInstanceId + ")");
                    exception.printStackTrace();
                }
            });
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

    public static ProcessUnit get(@NotNull ProcessPojo processPojo) {
        if (processPojo == null) {
            throw new NullPointerException("processPojo is null");
        }
        StackTraceElement stackTrace = Thread.currentThread().getStackTrace()[2];
        return INSTANCE.startProcessInstance(stackTrace, processPojo);
    }

}
